/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
// RUN: %clang2mpl --ascii --verify --simple-short-circuit %s -- -Wno-unused-value --target=aarch64-linux-elf
// RUN: cat %m | %FileCheck %s

int x[4];

struct A {
  int x;
  int y;
} gA, *gpA;

void unop(int a, int *b) {
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: (addrof a64 %a)
  &a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: array 0 a64 <* <[4] i32>> (addrof a64 $x, constval i32 2)
  &x[2];
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: iread i32 <* i32> 0 (dread a64 %b)
  *b;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dread i32 %a
  +a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: neg i32 (dread i32 %a)
  -a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: bnot i32 (dread i32 %a)
  ~a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: eq i32 i32 (dread i32 %a, constval i32 0)
  !a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: addrof a64 $gA 1
  &gA.x;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: iaddrof a64 <* <$A>> 2 (dread a64 $gpA)
  &gpA->y;
}

void prepost(int a, char *c, float *f) {
  // CHECK: var %post.[[#POST1:]] i32
  // CHECK: var %post.[[#POST2:]] i32
  // CHECK: var %post.[[#POST3:]] i32
  // CHECK: var %post.[[#POST4:]] i32
  // CHECK: var %post.[[#POST5:]] i32
  // CHECK: var %post.[[#POST6:]] i32
  // CHECK: var %post.[[#POST7:]] <* u8>
  // CHECK: var %post.[[#POST8:]] <* u8>
  // CHECK: var %post.[[#POST9:]] <* f32>
  // CHECK: var %post.[[#POST10:]] <* f32>

  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST1]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %w 0 (dread i32 %post.[[#POST1]])
  int w = a++;
  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST2]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %a 0 (sub i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %x 0 (dread i32 %post.[[#POST2]])
  int x = a--;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %y 0 (dread i32 %a)
  int y = ++a;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %a 0 (sub i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %z 0 (dread i32 %a)
  int z = --a;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST3]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  a++;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST4]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %a 0 (sub i32 (dread i32 %a, constval i32 1))
  a--;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  ++a;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %a 0 (sub i32 (dread i32 %a, constval i32 1))
  --a;
  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST5]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %x 0 (dread i32 %post.[[#POST5]])
  x = a++;
  // CHECK: LOC 2 [[# @LINE + 4 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST6]] 0 (dread i32 %a)
  // CHECK-NEXT: dassign %a 0 (sub i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %x 0 (dread i32 %post.[[#POST6]])
  x = a--;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %a 0 (add i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %x 0 (dread i32 %a)
  x = ++a;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %a 0 (sub i32 (dread i32 %a, constval i32 1))
  // CHECK-NEXT: dassign %x 0 (dread i32 %a)
  x = --a;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST7]] 0 (dread a64 %c)
  // CHECK-NEXT: dassign %c 0 (add a64 (dread a64 %c, constval u64 1))
  c++;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST8]] 0 (dread a64 %c)
  // CHECK-NEXT: dassign %c 0 (sub a64 (dread a64 %c, constval u64 1))
  c--;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %c 0 (add a64 (dread a64 %c, constval u64 1))
  ++c;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %c 0 (sub a64 (dread a64 %c, constval u64 1))
  --c;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST9]] 0 (dread a64 %f)
  // CHECK-NEXT: dassign %f 0 (add a64 (dread a64 %f, constval u64 4))
  f++;
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#POST10]] 0 (dread a64 %f)
  // CHECK-NEXT: dassign %f 0 (sub a64 (dread a64 %f, constval u64 4))
  f--;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %f 0 (add a64 (dread a64 %f, constval u64 4))
  ++f;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign %f 0 (sub a64 (dread a64 %f, constval u64 4))
  --f;
}

void fieldPrepost() {
  // CHECK: LOC 2 [[# @LINE + 3 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#]] 0 (dread i32 $gA 2)
  // CHECK-NEXT: dassign $gA 2 (add i32 (dread i32 $gA 2, constval i32 1))
  gA.y++;
  // CHECK: LOC 2 [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: dassign $gA 2 (add i32 (dread i32 $gA 2, constval i32 1))
  ++gA.y;
  // CHECK: LOC 2 [[# @LINE + 7 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#]] 0 (iread i32 <* <$A>> 2 (dread a64 $gpA))
  // CHECK-NEXT: iassign <* <$A>> 2 (
  // CHECK-NEXT:   dread a64 $gpA,
  // CHECK-NEXT:   add i32 (
  // CHECK-NEXT:     iread i32 <* <$A>> 2 (dread a64 $gpA),
  // CHECK-NEXT:     constval i32 1))
  gpA->y++;
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: iassign <* <$A>> 2 (
  // CHECK-NEXT:   dread a64 $gpA,
  // CHECK-NEXT:   add i32 (
  // CHECK-NEXT:     iread i32 <* <$A>> 2 (dread a64 $gpA),
  // CHECK-NEXT:     constval i32 1))
  ++gpA->y;
}

void logicalAndOr() {
  int x, y;
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#PNUM0:]] 0 (dread i32 %x)
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: eval (cand i32 (
  // CHECK-NEXT:   ne i32 i32 (dread i32 %post.2229, constval i32 0),
  // CHECK-NEXT:   ne i32 i32 (dread i32 %y, constval i32 0)))
  x++ && y;
  // CHECK: LOC 2 [[# @LINE + 5 ]]{{$}}
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: eval (cand i32 (
  // CHECK-NEXT:   ne i32 i32 (dread i32 %x, constval i32 0),
  // CHECK-NEXT:   ne i32 i32 (dread i32 %y, constval i32 0)))
  ++x && y;
  // CHECK: LOC 2 [[# @LINE + 7 ]]{{$}}
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM0:]] 0 (ne i32 i32 (dread i32 %x, constval i32 0))
  // CHECK-NEXT: brfalse @Lshortcircuit.1 (dread i32 %_shortcircuit.[[#SSNUM0]])
  // CHECK-NEXT: dassign %post.[[#PNUM1:]] 0 (dread i32 %y)
  // CHECK-NEXT: dassign %y 0 (add i32 (dread i32 %y, constval i32 1))
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM0]] 0 (ne i32 i32 (dread i32 %post.[[#PNUM1]], constval i32 0))
  // CHECK-NEXT: @Lshortcircuit.1
  x && y++;
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM1:]] 0 (ne i32 i32 (dread i32 %x, constval i32 0))
  // CHECK-NEXT: brfalse @Lshortcircuit.2 (dread i32 %_shortcircuit.[[#SSNUM1]])
  // CHECK-NEXT: dassign %y 0 (add i32 (dread i32 %y, constval i32 1))
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM1]] 0 (ne i32 i32 (dread i32 %y, constval i32 0))
  // CHECK-NEXT: @Lshortcircuit.2
  x && ++y;
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: dassign %post.[[#PNUM2:]] 0 (dread i32 %x)
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: eval (cior i32 (
  // CHECK-NEXT:   ne i32 i32 (dread i32 %post.[[#PNUM2]], constval i32 0),
  // CHECK-NEXT:   ne i32 i32 (dread i32 %y, constval i32 0)))
  x++ || y;
  // CHECK: LOC 2 [[# @LINE + 5 ]]{{$}}
  // CHECK-NEXT: dassign %x 0 (add i32 (dread i32 %x, constval i32 1))
  // CHECK-NEXT: eval (cior i32 (
  // CHECK-NEXT:   ne i32 i32 (dread i32 %x, constval i32 0),
  // CHECK-NEXT:   ne i32 i32 (dread i32 %y, constval i32 0)))
  ++x || y;
  // CHECK: LOC 2 [[# @LINE + 7 ]]{{$}}
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM2:]] 0 (ne i32 i32 (dread i32 %x, constval i32 0))
  // CHECK-NEXT: brtrue @Lshortcircuit.3 (dread i32 %_shortcircuit.[[#SSNUM2]])
  // CHECK-NEXT: dassign %post.[[#PNUM3:]] 0 (dread i32 %y)
  // CHECK-NEXT: dassign %y 0 (add i32 (dread i32 %y, constval i32 1))
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM2]] 0 (ne i32 i32 (dread i32 %post.[[#PNUM3]], constval i32 0))
  // CHECK-NEXT: @Lshortcircuit.3
  x || y++;
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM4:]] 0 (ne i32 i32 (dread i32 %x, constval i32 0))
  // CHECK-NEXT: brtrue @Lshortcircuit.4 (dread i32 %_shortcircuit.[[#SSNUM4]])
  // CHECK-NEXT: dassign %y 0 (add i32 (dread i32 %y, constval i32 1))
  // CHECK-NEXT: dassign %_shortcircuit.[[#SSNUM4]] 0 (ne i32 i32 (dread i32 %y, constval i32 0))
  // CHECK-NEXT: @Lshortcircuit.4
  x || ++y;
}
